/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/userdata/UDCPinger.cpp,v 1.9 2003/11/21 16:12:58 itsme Exp $
 *
 *
 *  this module handles ping messages, 
 *  these messages are used to determine the line delay
 *
 */

#include "CPhone.h" // theApp  .. needs to be included before the others, to avoid 'new' error in stl_evc
#include "debug.h"

#include "UDCPinger.h"

#include "cphonedlg.h"
#include "userdatahandler.h"

#include <algorithm>

UDCPinger::UDCPinger(CCPhoneDlg& dlg) : m_dlg(dlg)
{
    reset();
    m_nr_pings_to_send= -1;
    theApp.m_ud->RegisterUserdataHandler(UDCLT_PINGER, this);
}

UDCPinger::~UDCPinger()
{
    theApp.m_ud->UnRegisterUserdataHandler(UDCLT_PINGER);
}

// interval is in milliseconds
void UDCPinger::Start(long interval, long size)
{
    m_interval= interval;
    m_size= size;
    if (m_interval==0)
    {
        StopSending();
        return;
    }
    reset();    // clear statistics counters

    debug("UDCPinger: send every %d seconds, of %d bytes\n", m_interval, size);
    SendPingMessage();
    if (m_nr_pings_to_send) {
        m_timerid= m_dlg.SetTimer(123, m_interval, UDCPinger::staticTimerProc);
        debug("ping timer: id=%d  interval=%d\n", m_timerid, m_interval);
    }
/*
'void (struct HWND__ *,unsigned int,unsigned int,unsigned long)' to 
'void (__cdecl *)(struct HWND__ *,unsigned int,unsigned int,unsigned long)'


 */      
}
bool UDCPinger::StopSending()
{
    m_interval= 0;
    m_size= 0;
    m_dlg.KillTimer(123);
    m_timerid= 0;

    m_nr_pings_to_send= -1;

    // erase display while no pings are being sent.
    m_roundtriptime= 0;
    UpdateDialog();

    debug("UDCPinger: stopped\n");

    return true;
}

void UDCPinger::SendPings(int nCount, int nInterval, int nSize)
{
    m_nr_pings_to_send= nCount;
    Start(nInterval, nSize);
}

void UDCPinger::reset()
{
    m_pingsSent= 0;
    m_pongsSent= 0;
    m_pingsReceived= 0;
    m_pongsReceived= 0;
    m_bytesReceived= 0;
    m_roundtriptime= 0;
}

bool UDCPinger::HandleUserdataMessage(const ByteVector& data)
{
    bool res= false;
    switch(data[0])
    {
    case PINGMSG_PING: 
        {
            res= theApp.m_pinger->HandlePingMessage(data);
        }
        break;
    case PINGMSG_PONG: 
        {
            res= theApp.m_pinger->HandlePongMessage(data);
        }
        break;
    }

    return res;
}


void CALLBACK UDCPinger::staticTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    theApp.m_pinger->TimerProc(hwnd, uMsg, idEvent, dwTime);
}


void UDCPinger::TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    SendPingMessage();
}


bool UDCPinger::HandlePingMessage(const ByteVector& msg)
{
    DwordVector items= bufunpack(msg, "CCCCVVV");

    int size= items[4];
    int pingid= items[1] | ((items[3]&0x0f)<<8);
    DWORD time_pingsent= items[5];

    m_pingsReceived++;
    m_bytesReceived += size;    // size

    bool res= SendPongMessage(size, pingid, time_pingsent);

    UpdateDialog();

    return res;
}


bool UDCPinger::HandlePongMessage(const ByteVector& msg)
{
    DwordVector items= bufunpack(msg, "CCCCVVV");
    int size= items[4];
    DWORD time_pingsent= items[5];

    DWORD time_pongreceived= GetTickCount();

    m_pongsReceived++;
    m_bytesReceived += size;
    m_roundtriptime= time_pongreceived-time_pingsent;

    UpdateDialog();

    return true;
}

bool UDCPinger::SendPingMessage()
{
    if (m_nr_pings_to_send==0)
    {
        StopSending();
        return true;
    }
    if (m_nr_pings_to_send>0)
        m_nr_pings_to_send--;

    int size= m_size > sizeof(PingMessage) ? m_size : sizeof(PingMessage);
    ByteVector msg;

    bufpack(msg, "CCCCVVV", 
        PINGMSG_PING, m_pingid&0xff, 0, (m_pingid&0xf00)>>8, 
        size, GetTickCount(), 0);

    msg.resize(size);

    m_pingid++;
    m_pingsSent++;

    return theApp.m_ud->SendSingleMessage(msg);
}
bool UDCPinger::SendPongMessage(int size, int pingid, DWORD time_pingsent)
{
    if (size < sizeof(PingMessage)) 
        size= sizeof(PingMessage);

    ByteVector msg;

    bufpack(msg, "CCCCVVV", 
        PINGMSG_PONG, pingid&0xff, m_pongid&0xff, ((pingid&0xf00)>>8) | ((m_pongid&0xf00)>>4),
        size, time_pingsent, GetTickCount());

    return theApp.m_ud->SendSingleMessage(msg);
}

void UDCPinger::UpdateDialog()
{
    m_dlg.SetRoundTripTime(m_roundtriptime, 0, 4000);
}
